
import ctypes
import sys
import os
import time
import json
import binascii
import os
import base64

from fontTools.unicodedata import block

from serial_operation import SerialOperation

cur_status = 0
so = SerialOperation()

def status_change(new_status):
    global cur_status
    print("status change to {} from {}".format(new_status, cur_status))
    cur_status = new_status

def save_image_to_file(filename):
    global so
    image_size = 0
    st = 0
    while True:
        if st == 0:
            buf = so.read(1)
            if buf[0] == 0x9A:
                st = 1
        elif st == 1:
            buf = so.read(1)
            if buf[0] == 0xd2:
                st = 2
        elif st == 2:
            buf = so.read(1)
            if buf[0] == 0x0:
                st = 3
        elif st == 3:
            buf = so.read(5)
            if buf[0] == 0xE1:
                print("image not exist")
                break
            else:
                image_size = int.from_bytes(buf[1:4], byteorder='little')
                print("find image size {}, {}".format(buf[1:4].hex(), image_size))
                break

    print("image size {}".format(image_size))
    remain = image_size
    f = open(filename, 'wb')
    readblock = 10240
    while remain > 0:
        if remain < 10240:
            readblock = remain
        print("readblock {}", readblock)
        buf = so.read(readblock)
        n = f.write(buf)
        print("write {} bytes".format(n))
        remain -= len(buf)
        print("remain: {}", format(remain))
    f.close()

def start_recv_image_data(count, angle):
    global so
    buf = bytearray([0x7A, 0xD2, 0x00])
    buf_count = count.to_bytes(4, byteorder='little')
    buf_angle = angle.to_bytes(1, byteorder='little')
    buf+=buf_count
    buf+=buf_angle
    time.sleep(0.5)
    print("send data:{} {} {} {} {} {} {} {}".format(buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]))
    ret = so.sendData(buf)
    print("send result {}", format(ret))
    filename = "./img-%d-%d.jpg" % (count, angle)
    save_image_to_file(filename)

seq_num = 0
def wind_get_seq():
    global seq_num
    if seq_num >= 6553500:
        seq_num = 1
    seq_num = seq_num + 1
    return seq_num

def wind_protocol_buf_req_version():
    header = {}
    num = wind_get_seq()
    header['timestamp'] = num
    header['seqNum'] = num
    header['cmdType'] = 0x91
    header['info'] = ""
    return json.dumps(header)

def wind_protocol_buf_req_take_photo():
    header = {}
    num = wind_get_seq()
    header['timestamp'] = num
    header['seqNum'] = num
    header['cmdType'] = 0x96
    header['info'] = ""
    return json.dumps(header)

def wind_protocol_buf_req_get_image(open_count, angle, start, length):
    header = {}
    num = wind_get_seq()
    header['timestamp'] = num
    header['seqNum'] = num
    header['cmdType'] = 0x93
    info = {'open_count': open_count, 'angle': angle, 'offset': start, 'length': length}
    header['info'] = info
    return json.dumps(header)

def wind_protocol_buf_req_system_info():
    header = {}
    num = wind_get_seq()
    header['timestamp'] = num
    header['seqNum'] = num
    header['cmdType'] = 0x92
    header['info'] = ""
    return json.dumps(header)

def wind_protocol_buf_req_device_check():
    header = {}
    num = wind_get_seq()
    header['timestamp'] = num
    header['seqNum'] = num
    header['cmdType'] = 0x97
    header['info'] = ""
    return json.dumps(header)

def wind_modbus_buf_req_generate(data):
    data_count = len(data)
    print("data count {}, data {}".format(data_count, data))
    buf = bytearray(data_count + 34)
    buf[0] = 0x01
    buf[1] = 0x17
    buf[2] = 0x00 # read start
    buf[3] = 0x00
    buf[4] = 0x00 # read count
    buf[5] = 0x80
    buf[6] = 0x00 # write start
    buf[7] = 0x00
    buf[8] = 0x00 # write count
    buf[9] = 0x1f
    buf[10] = 0x00
    all_count = data_count + 8
    b = all_count.to_bytes(1, byteorder='little')
    buf[11] = b[0]
    buf[12] = 0xFD
    buf[13] = 0xFC
    buf[14] = 0xFB
    buf[15] = 0xFA
    buf[16] = 0x64
    buf[17] = 0x00
    buf[18:19] = data_count.to_bytes(2, byteorder='little')
    buf[20:] = data.encode('utf-8')
    buf.append(0x00)
    buf.append(0x00)
    print(binascii.hexlify(buf))
    return buf
def wind_modbus_get_images(open_count, angle, offset, length):
    global so
    fd = open("./img-0-0.jpg", 'wb')
    offset = 0
    block_size = 2000
    whole_size = 0
    while True:
        buf = wind_modbus_buf_req_generate(
            wind_protocol_buf_req_get_image(open_count, angle, offset, block_size))
        so.sendData(buf)
        time.sleep(0.3)
        res = so.read(3000)
        print("step 4: receive data:len [{}] [{}]".format(len(res), res.hex()))
        if buf[0] == 0x01 and buf[1] == 0x17:
            len_data = int.from_bytes(res[2:4], byteorder='little')
            data = res[4:4 + len_data].decode('utf-8')
            print("len_data {}, real_data_len {} data [{}]".format(len_data, len(data), data))
            res_data = json.loads(data)
            if res_data['result']['error'] != 0:
                print("error code {}".format(res_data['result']['error']))
                break

            if whole_size == 0:
                whole_size = res_data['result']["size"]
                print("whole_size {}".format(whole_size))

            base64_data = res_data['result']["data"]
            origin_bytes = base64.b64decode(base64_data.encode('utf-8'))
            len_write = fd.write(origin_bytes)
            offset += len_write
            if block_size + offset > whole_size:
                block_size = whole_size - offset
            if offset >= whole_size:
                break
    fd.close()

def do_all_things():
    global so
    so.refresh()
    serial_index = input("Which port to use: ")
    isOpen = so.open(int(serial_index))
    print("open serial {} of {}", format(isOpen, serial_index))
    open_count = 0
    angle = 0
    step = 0;
    while True:
        if step == 0:
            buf = wind_modbus_buf_req_generate(wind_protocol_buf_req_version())
            so.sendData(buf)
            time.sleep(0.3)
            step = 1
        elif step == 1:
            buf = so.readUntil()
            print("step 1: receive data:{}".format(buf.hex()))
            if len(buf) == 0:
                step = 0
                continue
            if buf[0] == 0x01 and buf[1] == 0x17:
                len_data = int.from_bytes(buf[2:4], byteorder='little')
                data = buf[4:4+len_data].decode('utf-8')
                print("len_data {}, data [{}]".format(len_data, data))
                step = 2 # take photo and get image
                # step = 5 # query system info
                # step = 7 # check device
        elif step == 2:
            # send command to take picture
            buf = wind_modbus_buf_req_generate(wind_protocol_buf_req_take_photo())
            so.sendData(buf)
            time.sleep(0.3)
            step = 3
        elif step == 3:
            buf = so.readUntil()
            print("step 3: receive data:{}".format(buf.hex()))
            if buf[0] == 0x01 and buf[1] == 0x17:
                len_data = int.from_bytes(buf[2:4], byteorder='little')
                data = buf[4:4 + len_data].decode('utf-8')
                print("len_data {}, data [{}]".format(len_data, data))
                data_json = json.loads(data)
                if data_json['result']['error'] != 0:
                    print("error code {}".format(data_json['result']['error']))
                    step = 99
                else:
                    step = 4
                    open_count = 0
                    angle = 0
        elif step == 4:
            print("start to get image content and save")
            wind_modbus_get_images(open_count, angle, 0, 0)
            step = 99
            print("image write done")
        elif step == 5:
            buf = wind_modbus_buf_req_generate(wind_protocol_buf_req_system_info())
            so.sendData(buf)
            time.sleep(0.3)
            step = 6
        elif step == 6:
            buf = so.readUntil()
            print("step 6: receive data:{}".format(buf.hex()))
            if buf[0] == 0x01 and buf[1] == 0x17:
                len_data = int.from_bytes(buf[2:4], byteorder='little')
                data = buf[4:4 + len_data].decode('utf-8')
                print("len_data {}, data [{}]".format(len_data, data))
                data_json = json.loads(data)
                if data_json['result']['error'] != 0:
                    print("error code {}".format(data_json['result']['error']))
                    step = 5
                else:
                    cmd = data_json['result']['cmd']
                    open_count = data_json['result']['open_count']
                    angle = data_json['result']['angle']
                    print("success cmd {}, open_count {}, angle {}".format(cmd, open_count, angle))
                    if cmd == 0x02:
                        step = 4
                    else:
                        step = 5

            time.sleep(1)
        elif step == 7:
            buf = wind_modbus_buf_req_generate(wind_protocol_buf_req_device_check())
            so.sendData(buf)
            time.sleep(0.3)
            step = 8
        elif step == 8:
            buf = so.readUntil()
            print("step 8: receive data:{}".format(buf.hex()))
            if buf[0] == 0x01 and buf[1] == 0x17:
                len_data = int.from_bytes(buf[2:4], byteorder='little')
                data = buf[4:4 + len_data].decode('utf-8')
                print("len_data {}, data [{}]".format(len_data, data))
            step = 99
        elif step == 99:
            pass


def is_admin():
    if os.name != 'nt':
        return True
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False

if is_admin():
    # 你的脚本内容
    print("Running as admin")
else:
    # 重新以管理员权限运行脚本
    ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)

if __name__ == '__main__':
    print('Wind Test program')
    do_all_things()
